#include "game.h"
#include "ui_game.h"
#include <QLabel>
#include <time.h>
#include <QKeyEvent>
#include <QMessageBox>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QFile>
#include <QCloseEvent>
#include <QPropertyAnimation>
#include <QMediaPlayer>
#include <QTimer>
#include <QTime>
#include <QAudioOutput>

int CREATE_NUMBER[2] = {
    2,
    4
};

const int colWidth = 75;
const int rowHeight = 75;
const int xOffset = 10;
const int yOffset = 10;


game::game(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::game)
{
    ui->setupUi(this);

    this->setWindowTitle("2048ProMax");

    QTime currentTime = QTime::currentTime();
    int second = currentTime.second();
    srand(second);

    ptimer=new QTimer;
    connect(ptimer,SIGNAL(timeout()),this,SLOT(update()));

    m_bgWidget = new BGWidget(this);
    m_bgWidget->setGeometry(10,180,460,460);

    this->m_labelCount = 0;

    initGame();

    setScore();

    BGM(3);

    this->m_bgWidget->setFocus();


    connect(this,&game::GestureMove,this,&game::moveLabel);

    connect(this,&game::ScoreChange,this,&game::setScore);
}

void game::update()
{
    QTime current=QTime::currentTime();
    int t=this->baseTime.msecsTo(current);
    QTime showtime(0,0,0,0);
    showtime=showtime.addMSecs(t);
    showStr=showtime.toString("hh:mm:ss:zzz");
    ui->time->display(showStr);

}

game::~game()
{
    delete ui;
    releaseRes();
    delete m_bgWidget;
}

void game::createLabel()
{
    while(true){
        int row = rand() % 6;
        int col = rand() % 6;

        int index = rand() % 2;


        if(labels[row][col] != NULL){
            continue;
        }

        MyLabel *label=new MyLabel(CREATE_NUMBER[index]);
        int x = col * colWidth + xOffset;
        int y = row * rowHeight +yOffset;
        label->setGeometry(x,y,66,66);
        label->setParent(m_bgWidget);

        labels[row][col] = label;
        labels[row][col]->show();

        break;
    }

    ++m_labelCount;
}

void game::initGame()
{

    m_score = 0;
    m_highScore = 0;


    for(int row = 0;row < 6;++row)
    {
        for(int col = 0;col <6;++col)
        {
            labels[row][col] = NULL;
        }
    }


    QFile *file = new QFile("data.json");
    if(file->open(QIODevice::ReadOnly))
    {
        QByteArray ba = file->readAll();

        QJsonDocument d = QJsonDocument::fromJson(ba);
        QJsonObject json = d.object();
        QJsonValue value = json.value(QString("m_highScore"));
        QJsonValue score = json.value(QString("m_score"));


        m_highScore = value.toVariant().toInt();
        this->ui->best_2->setText(QString::number(m_highScore));


        m_score = score.toVariant().toInt();
        this->ui->score_3->setText(QString::number(m_score));


        QJsonValue labelsArr = json.value(QString("labels"));
        QJsonArray arr = labelsArr.toArray();
        for(int i = 0;i< arr.size(); i++)
        {
            QJsonValue labelValue = arr.at(i);
            QJsonArray arr1 = labelValue.toArray();
            for(int j = 0; j< arr1.size(); j++)
            {
                QJsonValue arrValue =  arr1.at(j);
                int oldValue = arrValue.toVariant().toInt();
                if(oldValue != 0)
                {
                    MyLabel *label=new MyLabel(oldValue);
                    int x = j * colWidth + xOffset;
                    int y = i * rowHeight +yOffset;
                    label->setGeometry(x,y,66,66);
                    label->setParent(m_bgWidget);

                    labels[i][j] = label;
                    labels[i][j]->show();

                    ++m_labelCount;
                }
            }
        }

        file->close();


    }
    else
    {

        for(int i=0;i<2;i++){
            createLabel();
        }
    }
}

void game::BGM(int x){
    player = new QMediaPlayer(this);
    audioOutput = new QAudioOutput(this);
    player->setAudioOutput(audioOutput );
    switch (x) {
    case 1:
        audioOutput->setVolume(100);
        player->setSource(QUrl("qrc:/new/1.mp3"));
        player->play();
        break;
    case 2:
        audioOutput->setVolume(100);
        player->setSource(QUrl("qrc:/new/2.mp3"));
        player->play();
        break;
    case 3:
        audioOutput->setVolume(100);
        player->setSource(QUrl("qrc:/new/audio.wav"));
        player->play();
        break;
    case 4:
        audioOutput->setVolume(100);
        player->setSource(QUrl("qrc:/new/audiob.wav"));
        player->play();
        break;
    case 5:
        audioOutput->setVolume(100);
        player->setSource(QUrl("qrc:/new/audioc.wav"));
        player->play();
        break;
    case 6:
        audioOutput->setVolume(100);
        player->setSource(QUrl("qrc:/new/audiod.wav"));
        player->play();
        break;
    case 7:
        audioOutput->setVolume(100);
        player->setSource(QUrl("qrc:/new/audioe.wav"));
        player->play();
        break;
    case 8:
        audioOutput->setVolume(100);
        player->setSource(QUrl("qrc:/new/audiof.wav"));
        player->play();
        break;
    case 9:
        audioOutput->setVolume(100);
        player->setSource(QUrl("qrc:/new/audiog.wav"));
        player->play();
        break;
    default:
        break;
    }

}

int m=0;

void game::scorecheck(){
    switch (m+m_score/1000) {
    case 1:
        BGM(5);
        m=1;
        break;
    case 6:
        BGM(6);
        m=2;
        break;
    case 12:
        BGM(7);
        m=3;
        break;
    case 53:
        BGM(8);
        m=4;
        break;
    case 104:
        BGM(8);
        m=5;
        break;
    default:
        break;
    }
}


bool game::merge(MyLabel *temp, int row, int col)
{
    if(temp != NULL)
    {

        if(temp->text() == labels[row][col]->text())
        {
            int x = labels[row][col]->x();
            int y = row * rowHeight + yOffset;


            QPropertyAnimation *animation = new QPropertyAnimation(temp,"geometry");
            animation->setStartValue(temp->geometry());
            animation->setEndValue(QRect(x,y,temp->width(),temp->height()));
            animation->setDuration(100);
            animation->setEasingCurve(QEasingCurve::Linear);
            animation->start(QAbstractAnimation::DeleteWhenStopped);

            int score = 2*labels[row][col]->text().toInt();
            labels[row][col]->reSetText(score);

            m_score += score;

            emit ScoreChange();

            --m_labelCount;

            return true;
        }
    }
    return false;
}

bool game::isMerge()
{
    for(int row = 0;row < 6;++row)
    {
        for(int col = 0;col <6;++col)
        {
            if(isMergeDown(row,col) || isMergeRight(row,col))
            {
                return true;
            }
        }
    }

    return false;
}

bool game::gameOver()
{
    bool flag = false;

    if(m_labelCount == 36)
    {
        bool isWin = isMerge();
        if(!isWin){

            QMessageBox::about(this, "信息", "失败!哈哈!");
            BGM(2);
            flag = true;
        }
    }
    else
    {

        for(int row = 0;row < 6;++row)
        {
            for(int col = 0;col <6;++col)
            {
                if(labels[row][col] != NULL && labels[row][col]->text() == "1073741824")
                {
                    QMessageBox::about(this, "信息", "恭喜，你赢了!");
                    BGM(4);
                    flag = true;
                    break;
                }
            }
            if(flag)
            {
                break;
            }
        }
    }

    if(flag)
    {

        releaseRes();
        m_labelCount = 0;

        m_score = 0;
        emit ScoreChange();

        for(int i=0;i<2;i++){
            createLabel();
        }
    }

    return flag;
}

void game::saveGame()
{
    QFile *file = new QFile("data.json");
    if(file->open(QIODevice::WriteOnly))
    {
        QJsonDocument d;
        QJsonObject json = d.object();


        QJsonArray arr;
        for(int i = 0;i< 6; i++)
        {
            QJsonArray arr1;
            for(int j = 0; j< 6; j++)
            {
                if(labels[i][j] != NULL)
                {
                    arr1.append(labels[i][j]->text());
                }
                else
                {
                    arr1.append(0);
                }
            }
            arr.append(arr1);
        }

        json.insert("labels",arr);

        json.insert("m_highScore",m_highScore);
        json.insert("m_score",m_score);
        d.setObject(json);
        QByteArray ba = d.toJson(QJsonDocument::Indented);


        file->write(ba);
        file->close();
    }
}

void game::releaseRes()
{
    for(int col = 0;col <6;++col)
    {
        for(int row = 0;row < 6;++row)
        {
            if(labels[row][col] != NULL)
            {
                delete labels[row][col];
                labels[row][col] = NULL;
            }
        }
    }
}

void game::closeEvent(QCloseEvent *event)
{
    saveGame();
}

void game::setScore()
{
    this->ui->score_3->setText(QString::number(m_score));
    if(m_score > m_highScore)
    {
        m_highScore = m_score;
        this->ui->best_2->setText(QString::number(m_highScore));
    }
}

void game::keyPressEvent(QKeyEvent *event)
{
    scorecheck();

    switch (event->key()) {
    case Qt::Key_Left:
        emit GestureMove(GestureDirect::LEFT);
        break;
    case Qt::Key_Right:
        emit GestureMove(GestureDirect::RIGHT);
        break;
    case Qt::Key_Down:
        emit GestureMove(GestureDirect::DOWN);
        break;
    case Qt::Key_Up:
        emit GestureMove(GestureDirect::UP);
        break;
    case Qt::Key_A:
        emit GestureMove(GestureDirect::LEFT);
        break;
    case Qt::Key_D:
        emit GestureMove(GestureDirect::RIGHT);
        break;
    case Qt::Key_S:
        emit GestureMove(GestureDirect::DOWN);
        break;
    case Qt::Key_W:
        emit GestureMove(GestureDirect::UP);
        break;
    default:
        break;
    }
    QWidget::keyPressEvent(event);
}

void game::moveLabel(GestureDirect direction)
{
    bool isMove = false;
    switch (direction) {
    case LEFT:
        isMove = moveLeft();
        break;
    case RIGHT:
        isMove = moveRight();
        break;
    case UP:
        isMove = moveUp();
        break;
    case DOWN:
        isMove = moveDown();
        break;
    default:
        break;
    }


    bool isOver = gameOver();


    if(isMove && !isOver){
        createLabel();
    }


    if(!isOver)
    {
        gameOver();
    }
}

void game::on_bt_restart_clicked()
{

    releaseRes();
    m_labelCount = 0;

    BGM(3);

    m_score = 0;
    emit ScoreChange();

    for(int i=0;i<2;i++){
        createLabel();
    }

    this->m_bgWidget->setFocus();
}


bool game::moveUp()
{
    bool isMove = false;
    int i , j ;
    for(int col = 0;col < 6;++col)
    {
        j = -1;
        for(int row = 0;row < 6;++row)
        {

            if(labels[row][col] == NULL)
            {
                i = row + 1;
                while(i < 6)
                {
                    MyLabel *temp = labels[i][col];
                    if(temp != NULL)
                    {
                        isMove = true;
                        bool flag = false;
                        if(j != (row-1))
                        {
                            flag= isMergeUp(i,col);
                        }
                        if(flag)
                        {
                            --row;
                            j = row;
                            --m_labelCount;
                        }else
                        {

                            labels[row][col] = temp;
                            j = -1;
                        }

                        int x = temp->x();
                        int y = row * rowHeight + yOffset;


                        QPropertyAnimation *animation = new QPropertyAnimation(temp,"geometry");

                        animation->setStartValue(temp->geometry());
                        animation->setEndValue(QRect(x,y,temp->width(),temp->height()));
                        animation->setDuration(100);

                        animation->setEasingCurve(QEasingCurve::Linear);
                        animation->start(QAbstractAnimation::DeleteWhenStopped);


                        if(flag){
                            int score = 2*labels[row][col]->text().toInt();
                            labels[row][col]->reSetText(score);

                            m_score += score;
                            emit ScoreChange();

                            delete temp;
                            temp = NULL;
                        }

                        labels[i][col] = NULL;
                        ++row;
                    }
                    ++i;
                }
            }
            else if(row + 1 < 6)
            {

                MyLabel *temp = labels[row + 1][col];
                bool flag = merge(temp,row,col);
                if(flag)
                {
                    isMove = true;
                    j = row;

                    delete labels[row + 1][col];
                    labels[row + 1][col] = NULL;
                }
            }
        }
    }

    return isMove;
}

bool game::moveDown()
{
    bool isMove = false;
    int i , j ;
    for(int col = 0;col <6;++col)
    {
        j = -1;
        for(int row = 5;row > -1;--row)
        {

            if(labels[row][col] == NULL)
            {
                i =row-1;
                while(i > -1)
                {
                    MyLabel *temp = labels[i][col];
                    if(temp != NULL)
                    {
                        isMove = true;

                        bool flag = false;
                        if(j != (row + 1))
                        {
                            flag= isMergeDown(i,col);
                        }
                        if(flag)
                        {
                            ++row;
                            j = row;
                            --m_labelCount;
                        }else
                        {

                            labels[row][col] = temp;
                            j = -1;
                        }

                        int x= temp->x();
                        int y = row * rowHeight + yOffset;

                        QPropertyAnimation *animation = new QPropertyAnimation(temp,"geometry");

                        animation->setStartValue(temp->geometry());
                        animation->setEndValue(QRect(x,y,temp->width(),temp->height()));
                        animation->setDuration(100);
                        animation->setEasingCurve(QEasingCurve::Linear);
                        animation->start(QAbstractAnimation::DeleteWhenStopped);


                        if(flag){
                            int score = 2*labels[row][col]->text().toInt();
                            labels[row][col]->reSetText(score);

                            m_score += score;
                            emit ScoreChange();

                            delete temp;
                            temp = NULL;
                        }

                        labels[i][col] = NULL;
                        --row;
                    }
                    --i;
                }
            }
            else if(row-1>=0)
            {
                MyLabel *temp = labels[row-1][col];
                bool flag = merge(temp,row,col);
                if(flag)
                {
                    isMove = true;
                    j = row;

                    delete labels[row-1][col];
                    labels[row-1][col] = NULL;
                }
            }
        }
    }
    return isMove;
}

bool game::moveLeft()
{
    bool isMove = false;
    int i , j ;

    for(int row = 0;row < 6;++row)
    {
        j = -1;
        for(int col = 0;col < 6;++col)
        {

            if(labels[row][col] == NULL)
            {
                i = col + 1;
                while(i < 6)
                {
                    MyLabel *temp = labels[row][i];
                    if(temp != NULL)
                    {
                        isMove = true;
                        bool flag = false;
                        if(j != (col-1))
                        {
                            flag= isMergeLeft(row,i);
                        }
                        if(flag)
                        {
                            --col;
                            j = col;
                            --m_labelCount;
                        }else
                        {

                            labels[row][col] = temp;
                            j = -1;
                        }

                        int x = col * colWidth + xOffset;
                        int y = temp->y();


                        QPropertyAnimation *animation = new QPropertyAnimation(temp,"geometry");

                        animation->setStartValue(temp->geometry());
                        animation->setEndValue(QRect(x,y,temp->width(),temp->height()));
                        animation->setDuration(100);
                        animation->setEasingCurve(QEasingCurve::Linear);
                        animation->start(QAbstractAnimation::DeleteWhenStopped);

                        if(flag){
                            int score = 2*labels[row][col]->text().toInt();
                            labels[row][col]->reSetText(score);

                            m_score += score;
                            emit ScoreChange();

                            delete temp;
                            temp = NULL;

                        }

                        labels[row][i] = NULL;
                        ++col;
                    }
                    ++i;
                }
            }
            else if(col + 1 < 6)
            {
                MyLabel *temp = labels[row][col+1];
                bool flag = merge(temp,row,col);
                if(flag)
                {
                    isMove = true;
                    j = col;
                    delete labels[row][col+1];
                    labels[row][col+1] = NULL;
                }
            }
        }
    }

    return isMove;
}

bool game::moveRight()
{
    bool isMove = false;
    int i , j ;
    for(int row = 0;row < 6;++row)
    {
        j=-1;
        for(int col = 5; col > -1;--col)
        {

            if(labels[row][col] == NULL)
            {
                i = col - 1;
                while(i > -1)
                {
                    MyLabel *temp = labels[row][i];
                    if(temp != NULL)
                    {
                        isMove = true;
                        bool flag = false;

                        if(j != (col + 1)){
                            flag = isMergeRight(row,i);
                        }

                        if(flag)
                        {
                            ++col;
                            j = col;
                            --m_labelCount;
                        }
                        else
                        {

                            labels[row][col] = temp;
                            j = -1;
                        }

                        int x = col * colWidth + xOffset;
                        int y = temp->y();


                        QPropertyAnimation *animation = new QPropertyAnimation(temp,"geometry");

                        animation->setStartValue(temp->geometry());
                        animation->setEndValue(QRect(x,y,temp->width(),temp->height()));
                        animation->setDuration(100);
                        animation->setEasingCurve(QEasingCurve::Linear);
                        animation->start(QAbstractAnimation::DeleteWhenStopped);

                        if(flag){
                            int score = 2*labels[row][col]->text().toInt();
                            labels[row][col]->reSetText(score);

                            m_score += score;
                            emit ScoreChange();

                            delete temp;
                            temp = NULL;
                        }

                        labels[row][i] = NULL;
                        --col;
                    }
                    --i;
                }
            }
            else if(col-1>=0)
            {
                MyLabel *temp = labels[row][col-1];
                bool flag = merge(temp,row,col);
                if(flag)
                {
                    isMove = true;
                    j = col;

                    delete labels[row][col-1];
                    labels[row][col-1] = NULL;
                }
            }
        }
    }
    return isMove;
}

bool game::isMergeUp(int row, int col)
{
    if(row != 0)
    {
        int up = row - 1;
        while((up >= 0) && (labels[up][col]==NULL))
        {
            --up;
        }

        if(up >=0 && labels[up][col]->text() == labels[row][col]->text())
        {
            return true;
        }
    }

    return false;
}

bool game::isMergeDown(int row, int col)
{
    if(row != 5)
    {
        int down = row + 1;
        while((down < 6) && (labels[down][col] == NULL))
        {
            ++down;
        }
        if(down < 6 && labels[down][col]->text() == labels[row][col]->text())
        {
            return true;
        }
    }

    return false;
}

bool game::isMergeLeft(int row, int col)
{
    if(col != 0)
    {
        int left = col - 1;
        while((left >=0 ) && (labels[row][left] == NULL))
        {
            --left;
        }

        if(left >= 0 && labels[row][left]->text() == labels[row][col]->text())
        {
            return true;
        }
    }

    return false;
}

bool game::isMergeRight(int row, int col)
{
    if(col != 5)
    {
        int right = col + 1;
        while((right < 6) && (labels[row][right] == NULL))
        {
            ++right;
        }
        if(right < 6 && labels[row][right]->text() == labels[row][col]->text())
        {
            return true;
        }
    }

    return false;
}


void game::on_start_clicked()
{
    baseTime=QTime::currentTime();
    ptimer->start(1);
}


void game::on_remake_clicked()
{
    if(ui->remake->text()=="停止"){
        ptimer->stop();
        ui->remake->setText("清零");
        ui->start->setEnabled(false);//开始按钮无法点击
        ui->stop->setEnabled(false);
    }else{
        ui->time->display("00:00:00:000") ;//清零

        ui->remake->setText("停止");
        ui->start->setEnabled(true);//开始按钮可以点击
        ui->stop->setEnabled(true);

    }
}


void game::on_stop_clicked()
{
    static QTime pauseTime;  //暂停时间【静态】
    if(ui->stop->text()=="暂停"){
        pauseTime=QTime::currentTime();//获取点击暂停时的当前时间
        ptimer->stop();
        ui->stop->setText("继续");
        ui->start->setEnabled(false);//开始按钮无法点击
        ui->remake->setEnabled(false);
    }else{
        QTime cut=QTime::currentTime();//继续时的时间
        int t=pauseTime.msecsTo(cut);//差值
        baseTime=baseTime.addMSecs(t);  //后延相应的tms继续计时
        ptimer->start(1);
        ui->stop->setText("暂停");
        ui->start->setEnabled(true);//开始按钮可以点击
        ui->remake->setEnabled(true);}
}
